package com.wilmar.base.dao;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.HibernateAccessor;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.wilmar.wbce.domain.BankPaidData;

public class Hibernate3DaoSupport<T, PK extends Serializable> extends HibernateDaoSupport implements DaoService {

	private Class<T> pojoClass;

	/**
	 * 初始化DAO，获取POJO类型
	 */
	public Hibernate3DaoSupport() {
		this.pojoClass = getSuperClassGenricType(getClass(), 0);
	}

	private Class<T> getSuperClassGenricType(Class clazz, int index) {
		java.lang.reflect.Type genType = clazz.getGenericSuperclass();
		if (genType instanceof ParameterizedType) {
			java.lang.reflect.Type params[] = ((ParameterizedType) genType).getActualTypeArguments();
			if (params != null && params.length >= index + 1)
				return (Class) params[index];
		}
		return null;
	}

	/**
	 * 获得该DAO对应的POJO类型
	 */
	public Class<T> getPojoClass() {
		return this.pojoClass;
	}

	/**
	 * 获得该DAO对应的POJO类型名
	 */
	public String getPojoClassName() {
		return getPojoClass().getName();
	}

	/**
	 * 加载所有的对象
	 */
	public List<T> loadAll() {
		return (List<T>) getHibernateTemplate().loadAll(getPojoClass());
	}

	/**
	 * 加载所有的对象
	 */
	public T load(PK id) {
		return (T) getHibernateTemplate().load(getPojoClass(), id);
	}

	/**
	 * 根据hql查询
	 * 
	 * @param map
	 */
	public List<T> findByMap(String hql, Map<String, Object> map) {
		if (map == null)
			map = new HashMap();
		Set<String> keys = map.keySet();
		String[] paramNames = new String[keys.size()];
		keys.toArray(paramNames);
		Object[] values = map.values().toArray();
		return (List<T>) getHibernateTemplate().findByNamedParam(hql, paramNames, values);
	}

	/**
	 * 根据hql查询
	 * 
	 * @param values
	 *            可变参数
	 */
	public List<T> find(String hql, Object... values) {
		return (List<T>) getHibernateTemplate().find(hql, values);
	}

	/**
	 * 根据hql查询
	 * 
	 * @param values
	 *            可变参数
	 */
	public T findUniqueResult(String hql, Object... values) {
		List<T> list = (List<T>) getHibernateTemplate().find(hql, values);
		if (list.size() > 0)
			return list.get(0);
		return null;
	}

	/**
	 * 根据条件加载对象
	 * 
	 * @param criteria
	 *            Criteria实例
	 */
	public List<T> findByCriteria(final Criteria criteria) {
		List list = criteria.list();
		return transformResults(list);
	}

	/**
	 * 根据条件加载对象
	 * 
	 * @param detachedCriteria
	 *            DetachedCriteria实例
	 */
	public List<T> findByCriteria(final DetachedCriteria detachedCriteria) {
		return (List<T>) getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session) throws HibernateException {
				Criteria criteria = detachedCriteria.getExecutableCriteria(session);
				List list = criteria.list();
				return transformResults(list);
			}
		}, true);
	}

	/**
	 * 根据给定的实例查找对象
	 */
	public List<T> findByExample(T instance) {
		List<T> results = (List<T>) getHibernateTemplate().findByExample(instance);
		return results;
	}

	/**
	 * 根据ID查找对象
	 */
	public T findById(PK id) {
		return (T) getHibernateTemplate().get(getPojoClassName(), id);
	}

	/**
	 * 根据某个具体属性进行查找
	 */
	public List<T> findByProperty(String propertyName, Object value) {
		String queryString = "from " + getPojoClassName() + " as model where model." + propertyName + "= ?";
		return (List<T>) getHibernateTemplate().find(queryString, value);
	}

	/**
	 * 新建对象实例化
	 */
	public PK save(T transientInstance) throws DataAccessException {
		return (PK) getHibernateTemplate().save(transientInstance);
	}

	/**
	 * 更新已存在的对象
	 */
	public void update(T transientInstance) {
		getHibernateTemplate().update(transientInstance);
	}

	/**
	 * 更新已存在的对象
	 */
	public void saveOrUpdate(T transientInstance) {
		getHibernateTemplate().saveOrUpdate(transientInstance);
	}

	/**
	 * 删除指定ID的对象
	 */
	public void delete(PK id) {
		T instance = findById(id);
		if (instance != null)
			getHibernateTemplate().delete(instance);
	}

	/**
	 * 删除指定对象
	 */
	public void delete(T persistentInstance) {
		getHibernateTemplate().delete(persistentInstance);
	}

	// 分页
	/**
	 * 根据Criteria加载分页，指定页大小和起始位置
	 */
	public PaginationSupport findPageByCriteria(final Criteria criteria, final int pageSize, final int startIndex) {
		int totalCount = getCountByCriteria(criteria);
		criteria.setProjection(null);
		List items = criteria.setFirstResult(startIndex).setMaxResults(pageSize).list();
		items = transformResults(items);
		PaginationSupport ps = new PaginationSupport(items, totalCount, pageSize, startIndex);
		return ps;
	}

	/**
	 * 根据Criteria加载分页，默认页大小，从第0条开始
	 */
	public PaginationSupport findPageByCriteria(final Criteria criteria) {
		return findPageByCriteria(criteria, PaginationSupport.PAGESIZE, 0);
	}

	/**
	 * 根据Criteria加载分页，默认页大小，从第0条开始
	 */
	public PaginationSupport findPageByCriteria(final DetachedCriteria criteria, int currPage, Order[] orders) {
		return findPageByCriteria(criteria, PaginationSupport.PAGESIZE, currPage, orders);
	}

	/**
	 * 根据Criteria加载分页，默认页大小，从第startIndex条开始
	 */
	public PaginationSupport findPageByCriteria(final Criteria criteria, final int startIndex) {
		return findPageByCriteria(criteria, PaginationSupport.PAGESIZE, startIndex);
	}

	/**
	 * 根据Criteria统计总数
	 */
	public int getCountByCriteria(final Criteria criteria) {
		Integer count = (Integer) criteria.setProjection(Projections.rowCount()).uniqueResult();
		return count.intValue();
	}

	/**
	 * 根据DetachedCriteria加载分页，指定页大小和起始位置
	 */
	@Deprecated
	public PaginationSupport findPageByCriteria(final DetachedCriteria detachedCriteria, final int pageSize, final int startIndex) {
		return (PaginationSupport) getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session) throws HibernateException {
				Criteria criteria = detachedCriteria.getExecutableCriteria(session);
				int totalCount = ((Integer) criteria.setProjection(Projections.rowCount()).uniqueResult()).intValue();
				criteria.setProjection(null);
				List items = criteria.setFirstResult(startIndex).setMaxResults(pageSize).list();
				items = transformResults(items);
				PaginationSupport ps = new PaginationSupport(items, totalCount, pageSize, startIndex);
				return ps;
			}
		}, true);
	}

	public PaginationSupport findPageByCriteria(final DetachedCriteria detachedCriteria, final int pageSize, final int startIndex,
			final Order[] orders) {
		return (PaginationSupport) getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session) throws HibernateException {
				Criteria criteria = detachedCriteria.getExecutableCriteria(session);
				int totalCount = ((Integer) criteria.setProjection(Projections.rowCount()).uniqueResult()).intValue();
				System.out.println(totalCount);
				criteria.setProjection(null);
				for (Order o : orders) {
					criteria.addOrder(o);
				}
				List items = criteria.setFirstResult(startIndex).setMaxResults(pageSize).list();
				items = transformResults(items);
				PaginationSupport ps = new PaginationSupport(items, totalCount, pageSize, startIndex);
				return ps;
			}
		}, true);
	}

	/**
	 * 根据DetachedCriteria加载分页，默认页大小，从第0条开始
	 */
	public PaginationSupport findPageByCriteria(final DetachedCriteria detachedCriteria) {
		return findPageByCriteria(detachedCriteria, PaginationSupport.PAGESIZE, 0);
	}

	/**
	 * 根据DetachedCriteria加载分页，默认页大小，从第startIndex条开始
	 */
	public PaginationSupport findPageByCriteria(final DetachedCriteria detachedCriteria, final int startIndex) {
		return findPageByCriteria(detachedCriteria, PaginationSupport.PAGESIZE, startIndex);
	}

	/**
	 * 根据DetachedCriteria统计总数
	 */
	public int getCountByCriteria(final DetachedCriteria detachedCriteria) {
		Integer count = (Integer) getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session) throws HibernateException {
				Criteria criteria = detachedCriteria.getExecutableCriteria(session);
				return criteria.setProjection(Projections.rowCount()).uniqueResult();
			}
		}, true);
		return count.intValue();
	}

	/**
	 * 根据hql加载分页，指定页大小和起始位置
	 */
	public PaginationSupport findPageByQuery(final String hql, final int pageSize, final int startIndex, Object... values) {
		int totalCount = getCountByQuery(hql, values);

		if (totalCount < 1)
			return new PaginationSupport(new ArrayList(0), 0);

		Query query = createQuery(hql, values);
		List items = query.setFirstResult(startIndex).setMaxResults(pageSize).list();
		PaginationSupport ps = new PaginationSupport(items, totalCount, pageSize, startIndex);
		return ps;
	}

	/**
	 * 根据hql加载分页，默认页大小，从第0条开始
	 */
	public PaginationSupport findPageByQuery(final String hql, Object... values) {
		return findPageByQuery(hql, PaginationSupport.PAGESIZE, 0, values);
	}

	/**
	 * 根据hql加载分页，默认页大小，从第startIndex条开始
	 */
	public PaginationSupport findPageByQuery(final String hql, final int startIndex, Object... values) {
		return findPageByQuery(hql, PaginationSupport.PAGESIZE, startIndex, values);
	}

	/**
	 * 根据hql统计总数
	 */
	public int getCountByQuery(final String hql, Object... values) {
		String countQueryString = " select count (*) " + removeSelect(removeOrders(hql));
		List countlist = getHibernateTemplate().find(countQueryString, values);
		return ((Long) countlist.get(0)).intValue();
	}

	// 创建Criteria和Query

	/**
	 * 创建Criteria对象
	 * 
	 * @param criterions
	 *            可变的Restrictions条件列表
	 */
	public Criteria createCriteria(Criterion... criterions) {
		Criteria criteria = getSession().createCriteria(getPojoClass());
		for (Criterion c : criterions)
			criteria.add(c);
		return criteria;
	}

	/**
	 * 创建Criteria对象，带排序字段与升降序字段
	 */
	public Criteria createCriteria(String orderBy, boolean isAsc, Criterion... criterions) {
		Criteria criteria = createCriteria(criterions);
		if (isAsc)
			criteria.addOrder(Order.asc(orderBy));
		else
			criteria.addOrder(Order.desc(orderBy));
		return criteria;
	}

	/**
	 * 调用方式如下：
	 * 
	 * <pre>
	 *                            dao.createQuery(hql)   
	 *                            dao.createQuery(hql,arg0);   
	 *                            dao.createQuery(hql,arg0,arg1);   
	 *                            dao.createQuery(hql,new Object[arg0,arg1,arg2])
	 * </pre>
	 * 
	 * @param values
	 *            可变参数.
	 */
	public Query createQuery(String hql, Object... values) {

		Query query = getSession().createQuery(hql);

		for (int i = 0; i < values.length; i++) {
			query.setParameter(i, values[i]);
		}
		return query;
	}

	/**
	 * 去除hql的select子句，未考虑union的情况
	 */
	static String removeSelect(String hql) {
		int beginPos = hql.toLowerCase().indexOf("from");
		return hql.substring(beginPos);
	}

	/**
	 * 方法取自SpringSide. 去除hql的orderby子句
	 */
	static String removeOrders(String hql) {
		Pattern p = Pattern.compile("order\\s*by[\\w|\\W|\\s|\\S]*", Pattern.CASE_INSENSITIVE);
		Matcher m = p.matcher(hql);
		StringBuffer sb = new StringBuffer();
		while (m.find()) {
			m.appendReplacement(sb, "");
		}
		m.appendTail(sb);
		return sb.toString();
	}

	/**
	 * 将联合查询的结果内容从Map或者Object[]转换为实体类型，如果没有转换必要则直接返回
	 */
	List transformResults(List items) {

		if (items.size() > 0) {
			if (items.get(0) instanceof Map) {
				ArrayList list = new ArrayList(items.size());
				for (int i = 0; i < items.size(); i++) {
					Map map = (Map) items.get(i);
					list.add(map.get(CriteriaSpecification.ROOT_ALIAS));
				}
				return list;
			} else if (items.get(0) instanceof Object[]) {
				ArrayList list = new ArrayList(items.size());
				int pos = 0;
				for (int i = 0; i < ((Object[]) items.get(0)).length; i++) {
					if (((Object[]) items.get(0))[i] != null && ((Object[]) items.get(0))[i].getClass() == getPojoClass()) {
						pos = i;
						break;
					}
				}
				for (int i = 0; i < items.size(); i++) {
					list.add(((Object[]) items.get(i))[pos]);
				}
				return list;
			} else
				return items;
		} else
			return items;
	}

	public Collection<T> filterCollection(Collection<T> collection, String filter) {
		Query filterQuery = this.getSession().createFilter(collection, filter);
		return filterQuery.list();
	}

	public Collection<T> filterCollection(Collection<T> collection) {
		Query filterQuery = this.getSession().createFilter(collection, "");
		return filterQuery.list();
	}

	public int executeUpdate(String hql, Object... values) {

		Query query = getSession().createQuery(hql);
		for (int i = 0; i < values.length; i++) {
			query.setParameter(i, values[i]);
		}
		return query.executeUpdate();
	}

	/**
	 * 执行采用本地SQL
	 * 
	 * @param sql
	 * @param values
	 * @return
	 */
	public List queryBySQL(String sql, Object... values) {
		Query query = createSQLQuery(sql, values);
		return query.list();
	}

	/**
	 * 根据sql加载分页，默认页大小，从第0条开始
	 * 
	 * @lastmodify : 徐炉南 xinlunan487@163.com 2010-3-25
	 * @param sql
	 * @param values
	 * @return PaginationSupport
	 */
	public PaginationSupport findPageByQuerySQL(final String sql, Object... values) {
		return findPageByQuerySQL(sql, PaginationSupport.PAGESIZE, 0, values);
	}

	/**
	 * 根据sql加载分页，默认页大小，从第startIndex条开始
	 * 
	 * @lastmodify : 徐炉南 xinlunan487@163.com 2010-3-25
	 * @param sql
	 * @param startIndex
	 * @param values
	 * @return PaginationSupport
	 */
	public PaginationSupport findPageByQuerySQL(final String sql, final int startIndex, Object... values) {
		return findPageByQuerySQL(sql, PaginationSupport.PAGESIZE, startIndex, values);
	}

	/**
	 * 根据hql加载分页，指定页大小和起始位置
	 * 
	 * @lastmodify : 徐炉南 xinlunan487@163.com 2010-3-25
	 * @param sql
	 * @param pageSize
	 * @param startIndex
	 * @param values
	 * @return PaginationSupport
	 */
	public PaginationSupport findPageByQuerySQL(final String sql, final int pageSize, final int startIndex, Object... values) {
		int totalCount = getCountByQuerySQL(sql, values);

		if (totalCount < 1)
			return new PaginationSupport(new ArrayList(0), 0);

		Query query = createSQLQuery(sql, values);
		List items = query.setFirstResult(startIndex).setMaxResults(pageSize).list();
		PaginationSupport ps = new PaginationSupport(items, totalCount, pageSize, startIndex);
		return ps;
	}

	/**
	 * 得到总的记录数
	 * 
	 * @lastmodify : 徐炉南 xinlunan487@163.com 2010-3-26
	 * @param sql
	 * @param values
	 * @return int
	 */
	public int getCountByQuerySQL(String sql, Object... values) {
		int fromPos = sql.toLowerCase().indexOf("from");
		int distinctPos = sql.toLowerCase().indexOf("distinct");
		if (distinctPos == -1) {
			sql = "select count(*) as cnt " + sql.substring(fromPos);
			List<Object> tempList = new ArrayList<Object>();
			// 去除map元素
			for (int i = 0; i < values.length; i++) {
				if (!(values[i] instanceof Map)) {
					tempList.add(values[i]);
				}
			}
			Query query = createSQLQuery(sql, tempList.toArray());
			return (Integer) query.list().get(0);
		} else {// select 𧧅语句中带有distinct关键字时，无法重新拼凑，直接用原语句取总记录数
			Query query = createSQLQuery(sql, values);
			return query.list().size();
		}

	}

	/**
	 * 执行SQL查询语句
	 * 
	 * @lastmodify : 徐炉南 xinlunan487@163.com 2010-3-26
	 * @param sql
	 * @param values
	 * @return Query
	 */
	public Query createSQLQuery(String sql, Object... values) {

		SQLQuery query = getSession().createSQLQuery(sql);
		for (int i = 0; i < values.length; i++) {
			if (values[i] instanceof Map) {
				Map map = (Map) values[i];
				Set set = map.entrySet();
				Iterator iterator = set.iterator();
				while (iterator.hasNext()) {
					Map.Entry mapentry = (Map.Entry) iterator.next();
					query.addEntity((String) mapentry.getKey(), (Class) mapentry.getValue());
				}
			} else {
				query.setParameter(i, values[i]);
			}

		}
		return query;
	}

	/**
	 * 查询指定列
	 * @param proxy
	 */
	public List createSQLQuery(String sql) {
		List list = getSession().createSQLQuery(sql).list();
		return  list;
		
	}

	public void initialize(Object proxy) {
		this.getHibernateTemplate().initialize(proxy);
	}

	public void flush() {
		this.getHibernateTemplate().flush();
		this.getHibernateTemplate().clear();
	}

	public void alwaysFlush() {
		this.getHibernateTemplate().setFlushMode(HibernateAccessor.FLUSH_ALWAYS);
	}

	public void eagerFlush() {
		this.getHibernateTemplate().setFlushMode(HibernateAccessor.FLUSH_EAGER);
	}

	public void restoreDefaultFlush() {
		this.getHibernateTemplate().setFlushMode(HibernateAccessor.FLUSH_AUTO);
	}
}
